package cn.sycoder.config;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

@Aspect
@Component
public class LoggingAspect {

    private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);

    // 定义一个切点，拦截所有Controller中的方法  
    @Pointcut("execution(* cn.sycoder.controller..*(..))")
    public void controllerMethods() {
    }

    // 定义一个切点，拦截所有Repository中的方法  
    @Pointcut("execution(* cn.sycoder.mapper..*(..))")
    public void repositoryMethods() {
    }

    // 定义一个环绕通知，在controllerMethods或repositoryMethods切点匹配的方法执行前后执行
    @Around("controllerMethods() || repositoryMethods()")
    public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis(); // 记录方法执行前的时间

        // 获取方法信息  
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        String methodName = method.getDeclaringClass().getSimpleName() + "." + method.getName();  

        // 获取请求信息（仅在Controller层有效）
        String requestURI = "";
        String requestMethod = "";
        Map<String, String[]> requestParams = new HashMap<>();
        // 判断当前被拦截的方法是否属于Controller层
        if (joinPoint.getSignature().getDeclaringType().getName().startsWith("cn.sycoder.controller")) {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes != null) {
                HttpServletRequest request = attributes.getRequest();
                requestURI = request.getRequestURI(); // 获取请求路径
                requestMethod = request.getMethod(); // 获取请求方法
                requestParams = request.getParameterMap(); // 获取请求参数
            }
        }

        // 打印请求参数（仅在Controller层有效）
        if (!requestParams.isEmpty()) {
            StringBuilder paramsLog = new StringBuilder("Params: {"); // 创建集合进行拼接请求参数
            for (Map.Entry<String, String[]> entry : requestParams.entrySet()) { // 迭代遍历
                paramsLog.append(entry.getKey()).append("=[");
                for (String value : entry.getValue()) {
                    paramsLog.append(value).append(",");
                }
                // 移除最后一个逗号并添加闭合括号和逗号分隔符（用于多个参数）
                if (entry.getValue().length > 0) {
                    paramsLog.setLength(paramsLog.length() - 1); // 移除最后一个逗号
                }
                paramsLog.append("], ");
            }
            // 移除最后一个逗号和空格，并添加闭合括号
            if (paramsLog.length() > "Params: {".length()) {
                paramsLog.setLength(paramsLog.length() - 2); // 移除最后一个逗号和空格
            }
            paramsLog.append("}");
            logger.info(paramsLog.toString()); // 打印请求参数
        }

        // 执行方法  
        Object proceed = joinPoint.proceed();

        // 计算耗时  
        long executionTime = System.currentTimeMillis() - start;

        // 打印日志  
        String logMessage = String.format("URI: %s, Method: %s, ClassMethod: %s, ExecutionTime: %d ms",
                requestURI, requestMethod, methodName, executionTime); // 请求路径，请求方法，方法名，消耗时间
        logger.info(logMessage);

        return proceed;
    }

}